﻿namespace zijian666.WorkScheduler.Defines;

/// <summary>
/// 表示一个门
/// </summary>
internal class TheDoor : IDisposable
{
    private TaskCompletionSource<bool> _sign = new();
    private bool _disposed;
    /// <summary>
    /// 获取开关状态
    /// </summary>
    public bool IsOpen => !_disposed && _sign.Task.IsCompleted;

    /// <summary>
    /// 获取开关状态
    /// </summary>
    public bool IsClosed => _disposed || !IsOpen;

    /// <summary>
    /// 等待开启
    /// </summary>
    public async Task WaitOpen(CancellationToken cancellation)
    {
        this.ThrowIfDisposed(_disposed);
#if NET6_0_OR_GREATER
        while (!await _sign.Task.WaitAsync(cancellation)) { }
#else
        var sign = _sign;
        cancellation.Register(() => sign.TrySetCanceled());
        while (!await sign.Task) { }
#endif
    }

    /// <summary>
    /// 开启
    /// </summary>
    public void Open()
    {
        this.ThrowIfDisposed(_disposed);
        _sign.TrySetResult(true);
    }

    /// <summary>
    /// 关闭
    /// </summary>
    public void Close()
    {
        this.ThrowIfDisposed(_disposed);
        if (IsClosed)
        {
            return;
        }
        var old = Interlocked.CompareExchange(ref _sign, new(), _sign);
        if (old.Task.IsFaulted)
        {
            Interlocked.Exchange(ref _sign, old);
            this.ThrowIfDisposed(true);
        }
        if (!old.Task.IsCompleted)
        {
            old.TrySetResult(false);
        }
    }

    /// <summary>
    /// 释放资源
    /// </summary>
    public void Dispose()
    {
        _disposed = true;
        _sign.TrySetException(new ObjectDisposedException(nameof(TheDoor)));
    }
}
